using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using XNACamera;

namespace PlaneGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        double totalTangage;
        double totalLacet;

        Model terrain;
        CameraSpherique camera;
        HeightMapInfo heightMapInfo;
        Avion monAvion;
        int i;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            camera = new CameraSpherique(this);
            camera.Rho = 100;
            camera.ZMax = 100000;

            monAvion = new Avion(this);
            monAvion.Camera = camera;
            monAvion.Vitesse = 0;

            Components.Add(monAvion);
            monAvion.Vitesse = 4;

            Matrix m1 = Matrix.CreateFromYawPitchRoll(1, 1, 1);
            Matrix m2 = Matrix.CreateRotationX(1) * Matrix.CreateRotationY(1) * Matrix.CreateRotationZ(1);



            Console.WriteLine(m1.ToString());
            Console.WriteLine(m2.ToString());
            i = 0;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            
            spriteBatch = new SpriteBatch(GraphicsDevice);
            
            terrain = Content.Load<Model>("terrain");
            heightMapInfo = terrain.Tag as HeightMapInfo;


            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            int milieuX = GraphicsDevice.DisplayMode.Width/2;
            int milieuY = GraphicsDevice.DisplayMode.Height / 2;
            IsMouseVisible = true;
            
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();

            if (!heightMapInfo.IsOnHeightmap(monAvion.Position))
            {
                this.Initialize();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                camera.Theta += 0.01f;
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Space))
            {
                monAvion.Vitesse += 0.1f;
            }


            monAvion.Roulis -= (Mouse.GetState().X - milieuX)* 0.005f;
            //monAvion.Lacet = monAvion.Roulis / 10;
            monAvion.Tangage += (Mouse.GetState().Y - milieuY) * 0.005f;
            monAvion.Ascent += (Mouse.GetState().Y - milieuY) * 0.005f;

            

            if (Keyboard.GetState().IsKeyDown(Keys.Z))
            {
                camera.Phi += 0.01f;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Q))
            {
                
                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                {
                    totalLacet += Math.Sin(monAvion.Roulis)/10;
                    totalTangage -= Math.Cos(monAvion.Roulis)/10;
                }
                else if (Keyboard.GetState().IsKeyDown(Keys.Right))
                {
                    totalLacet -= Math.Sin(monAvion.Roulis)/5;
                    totalTangage += Math.Cos(monAvion.Roulis) / 10;
                }
                else
                {
                    totalLacet -= Math.Sin(monAvion.Roulis)*3;
                }
            }
            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                camera.Phi -= 0.01f;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                {
                    totalLacet -= Math.Sin(monAvion.Roulis) / 5;
                    totalTangage += Math.Cos(monAvion.Roulis) / 10;
                }
                else if (Keyboard.GetState().IsKeyDown(Keys.Right))
                {
                    totalLacet += Math.Sin(monAvion.Roulis) / 10;
                    totalTangage -= Math.Cos(monAvion.Roulis) / 10;
                }
                else
                {
                    totalLacet += Math.Sin(monAvion.Roulis) * 3;
                }
            }


            double coef = 0.1f;
            float coef2 = 0.1f;
            if (Keyboard.GetState().IsKeyDown(Keys.Up))
            {
                totalTangage -= Math.Cos(monAvion.Roulis)/10;
                totalLacet -=  Math.Sin(monAvion.Roulis)/10;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Down))
            {
                totalTangage +=Math.Cos(monAvion.Roulis)/10;
                totalLacet += Math.Sin(monAvion.Roulis)/10;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                if (monAvion.Roulis >= -0.9)
                {
                    monAvion.Roulis -= coef2 / 2;
                }
                totalLacet += monAvion.Roulis / 10;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                if (monAvion.Roulis <= 0.9)
                {
                    monAvion.Roulis += coef2 / 2;
                }
                totalLacet += monAvion.Roulis / 10;
            }

            // TODO: Add your update logic here
            Mouse.SetPosition(milieuX, milieuY);
       
            monAvion.Lacet = (float)(totalLacet * coef);
            monAvion.Tangage = (float)(totalTangage * coef);
            if (monAvion.Roulis <= 0 && Keyboard.GetState().IsKeyUp(Keys.Right))
            {
                monAvion.Roulis += coef2 / 2;
            }
            if (monAvion.Roulis >= 0 && Keyboard.GetState().IsKeyUp(Keys.Left))
            {
                monAvion.Roulis -= coef2 / 2;
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            // TODO: Add your drawing code here
            DrawModel(terrain, monAvion.Camera, Matrix.Identity);
            base.Draw(gameTime);
        }

        void DrawModel(Model model, Camera cam, Matrix matPlacement)
        {
            Matrix[] boneTransforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(boneTransforms);
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = boneTransforms[mesh.ParentBone.Index] *
                    matPlacement;
                    effect.View = camera.View;
                    effect.Projection = camera.Projection;
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    // Set the fog to match the black background color
                    effect.FogEnabled = true;
                    effect.FogColor = Vector3.Zero;
                    effect.FogStart = 1000;
                    effect.FogEnd = 3200;
                }
                mesh.Draw();
            }
        }
    }
}
